<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <iframe
      src="./web worker.html"
      frameborder="0"
      width="500px"
      height="500px"
    ></iframe>
    <script src="./index.js"></script>

    <script>
      // 1.找出字符串中重复次数最多的字符；并返回重复次数；
      // 2.obj.a.b.c.d  计算
      // 3.树状结构转平铺；平铺转树状结构
      // let treeToArray = function f(treeData) {
      //   // 这时的 f 只是变量的treeToArray指向函数的内部标识符(外部是访问不到的)
      //   "use strict"; // 开启函数下的严格模式
      //   let res = treeData.reduce((pre, item, index) => {
      //     const { children, ...i } = item;
      //     return pre.concat(i, children?.length ? f(children) : []);
      //   }, []);
      //   return res;
      // };
      // let fn = treeToArray;
      // treeToArray = null;
      // console.log(fn(treeData));

      // 4.数组去重 6种方法：1.双重for循环 2. [...new Set(arr)] 3.Array.from(new Set(arr)) 4.for循环+indexOf 5.for循环+ includes 6.filter
      // 5.Object.values ,Object.entries, 数组falt(num); 数组的深度遍历，并转换为单个元素的数组；
      // 6.数组对象的排序
      // 7.生成随机数
      // 8.合并空值运算符 ??"";判断数组 / 对象中是否有空值
      // 9.链式操作符  obj?.name === obj && obj.name
      // 10.模拟重载函数  就是函数的一种特殊情况； 同名函数 但因参数的类型、个数。或者顺序不同；而可以实现不同功能的函数；js没有重载函数
      // 11.Web Worker 工作线程 专用线程（Dedicated Web Worker）和共享线程（Shared Web Worker）
      // 12.实现一个new函数
      function myNew(fn) {
        let args = Array.prototype.slice.call(arguments, 1);
        const res = Object.create(fn.prototype);
        let result = fn.apply(res, args); // new 构造函数的返回值 是由执行完构造函数的返回值来确定 如果返回值是引用类型 就返回该值；如果是值类型，就返回新创建的对象
        if (Object.prototype.toString.call(result) === "[object Null]") {
          return res;
        }
        return typeof result === "object" || result instanceof Function
          ? result
          : res;
      }
      // 13.防抖和节流  输入框的输入性能优化
      // 14.函数柯里化  利用闭包 把多个参数传进一个函数  改写成一个参数传进后 ；返回一个函数处理接下的参数  的函数

      // 15.手动实现 call apply bind(函数柯里化)  一个构造函数bind 绑定了一个对象; new 这个构造函数得到实例里面会有 绑定的对象里面的属性吗？ 实现bind的时候考虑？
      Function.prototype.newcall = function (content, ...args) {
        content = content == undefined ? window : Object(content); // 如果第一个参数 为null/undedfined ;则 content 指向window
        let result;
        content.fn = this; // 让content 这个对象上有方法  这个this 就是调用 newcall方法的函数  理解函数也是对象概念
        result = content.fn(...args);
        delete content.fn; // 再从这个对象上把这个方法删除
        return result;
      };
      Function.prototype.newApply = function (content, args) {
        if (!Array.isArray(args)) {
          throw new Error(args + "is not a Array");
        }
        content = content == undefined ? window : Object(content); // 如果第一个参数 为null/undedfined ;则 content 指向window
        let result;
        content.fn = this; // 让content 这个对象上有方法  这个this 就是调用 newcall方法的函数  理解函数也是对象概念
        result = content.fn(...args);
        delete content.fn; // 再从这个对象上把这个方法删除
        return result;
      };
      Function.prototype.myBind = function (content) {
        if (typeof content !== "function") {
          throw new Error(content + "is not a function");
        }
        const args1 = Array.prototype.slice.call(arguments, 1); // 获取调用bind时传递的参数
        const _self = this; // _self 指的是调用 bind 方法的那个函数（对象）；
        const newFun = function () {
          const args2 = Array.prototype.slice.call(arguments); // 返回的函数传入的参数
          return _self.apply(
            this instanceof newFun ? this : content, // 如果是new;在执行这个方法时 则指向当前的实例 this;如果不是new,则指向content
            args1.concat(args2)
          );
        };
        newFun.prototype = Object.create(_self.prototype); // 让返回函数的prototype指向一个 原型为_self.prototype的对象
        return newFun;
      };
      // 16.Object.create(); 返回一个原型为传入参数的对象；且对象上有自定义的属性或方法(后面的参数或方法)
      Object.myCreate = function (obj, args) {
        if (
          Object.prototype.toString.call(obj) !==
          ("[object function]" || "[object object]")
        ) {
          throw new Error("error");
        }
        let Fn = function () {};
        Fn.prototype = obj;
        const newObj = new Fn();
        return newObj;
      };
      // 17.实现Object.assgin();
      // 18.手写数组扁平化 falt()方法

      // var name = " hhh";
      // let obj = {
      //   name: "haaaa",
      //   b: 2,
      // };

      // function sayname(value1, value2) {
      //   console.log(this.name + value1 + value2);
      // }

      // let newSayName = sayname.newBind(obj, 16);
      // newSayName(10);

      // const { a, b, c } = obj || {}; // 解构赋值  不能用于 null 和 undefined  可以写

      // 空值合并运算 ??""  用来判断某个值 是否是  "" null undefined;
      // console.log((value ?? "") === "");
      // const arr = [...new Set([...arr1, ...arr2])]; // 数组合并 并去重
      // const obj = { ...name, ...name1 }; // 比Object.assign()方法好用；自动去重

      function Person(name, age) {
        this.name = name;
        this.age = age;
      }
      let obj2 = {
        a: 1,
        b: 2,
      };

      let obj = Object.create(obj2);
      console.log(obj);

      let obj1 = Object.myCreate(obj2);
      console.log(obj1);
    </script>
  </body>
</html>
